using System;
using System.Xml;

namespace stunnware.CRM.Fetch {
   /// <summary>
   /// The FetchFilter is a collection of conditions.
   /// </summary>
   public class FetchFilter {

      private FetchFilterType _filterType;
      private readonly FetchConditionCollection _conditions = new FetchConditionCollection();
      private readonly FetchFilterCollection _filters = new FetchFilterCollection();

      /// <summary>
      /// Creates a new instance of the specified type.
      /// </summary>
      /// <param name="filterType"></param>      
      public FetchFilter(FetchFilterType filterType) {
         _filterType = filterType;
      }

      /// <summary>
      /// The filter type. 
      /// If set to AND, all <see cref="Conditions"/> and all <see cref="Filters"/> must be true in order for this
      /// filter to be true.
      /// If set to OR, at least one condition in <see cref="Conditions"/> or one filter in <see cref="Filters"/> must be true in order 
      /// for this filter to be true.
      /// </summary>
      public FetchFilterType FilterType {
         get {
            return _filterType;
         }

         set {
            _filterType = value;
         }
      }

      /// <summary>
      /// The conditions. 
      /// </summary>
      public FetchConditionCollection Conditions {
         get {
            return _conditions;
         }
      }

      /// <summary>
      /// The filters.
      /// </summary>
      public FetchFilterCollection Filters {
         get {
            return _filters;
         }
      }

      /// <summary>
      /// Adds the definition of this class to an XML document.
      /// </summary>
      /// <param name="entityNode"></param>
      internal void AddToFetchDocument(XmlElement entityNode) {

         XmlElement filterNode = FetchXmlDocument.AddElement(entityNode, "filter");

         if (FilterType == FetchFilterType.Or) {
            FetchXmlDocument.AddAttribute(filterNode, "type", "or");
         }

         if (Conditions != null) {
            foreach(FetchCondition condition in Conditions) {
               condition.AddToFetchDocument(filterNode);
            }
         }

         if (Filters != null) {
            foreach(FetchFilter filter in Filters) {
               filter.AddToFetchDocument(filterNode);
            }
         }
      }

      /// <summary>
      /// Parses the passed xml node and creates a new instance from it.
      /// </summary>
      /// <param name="node"></param>
      /// <returns></returns>
      public static FetchFilter FromXml(XmlNode node) {

         XmlAttribute attr = node.Attributes["type"];
         FetchFilterType filterType = FetchFilterType.And;

         if ((attr != null) && (attr.Value == "or")) {
            filterType = FetchFilterType.Or;
         }

         FetchFilter filter = new FetchFilter(filterType);

         XmlNodeList filterNodes = node.SelectNodes("filter");
         foreach(XmlNode filterNode in filterNodes) {
            filter.Filters.Add(FetchFilter.FromXml(filterNode));
         }

         XmlNodeList conditionNodes = node.SelectNodes("condition");
         foreach(XmlNode conditionNode in conditionNodes) {
            filter.Conditions.Add(FetchCondition.FromXml(conditionNode));
         }

         return filter;
      }
   }

   /// <summary>
   /// The fetch filter type.
   /// </summary>
   public enum FetchFilterType {
      /// <summary>
      /// And: All conditions in a filter must be met
      /// </summary>
      And,

      /// <summary>
      /// Or: At least one condition in a filter must be met
      /// </summary>
      Or
   }
}